package ca.scotthyndman.as2haxe.dom;

import java.util.ArrayList;
import java.util.List;

import ca.scotthyndman.as2haxe.dom.visitor.IVisitor;

/**
 * Represents a variable declaration wrapped in a statement.
 */
public class ASVariableDeclarationStatement extends ASStatement {

	/**
	 * The "declaration" structural property of this node type.
	 * 
	 * @since 3.0
	 */
	public static final ASChildPropertyDescriptor DECLARATION_PROPERTY = new ASChildPropertyDescriptor(
			ASVariableDeclarationStatement.class, "declaration",
			ASVariableDeclaration.class, true);

	/**
	 * A list of property descriptors (element type:
	 * {@link ASPropertyDescriptor}), or null if uninitialized.
	 */
	private static final List<ASPropertyDescriptor> PROPERTY_DESCRIPTORS;

	static {
		List<Object> properyList = new ArrayList<Object>(2);
		createPropertyList(ASVariableDeclarationStatement.class, properyList);
		addProperty(DECLARATION_PROPERTY, properyList);
		PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
	}

	/**
	 * Returns a list of structural property descriptors for this node type.
	 * Clients must not modify the result.
	 * 
	 * @return a list of property descriptors (element type:
	 *         {@link ASPropertyDescriptor})
	 */
	public static List<ASPropertyDescriptor> propertyDescriptors() {
		return PROPERTY_DESCRIPTORS;
	}

	//
	// ======== MEMBERS
	//

	ASVariableDeclaration declaration;

	/**
	 * Default constructor.
	 * 
	 */
	public ASVariableDeclarationStatement(AST ast) {
		super(ast);
	}

	/**
	 * Constructs the statement with an internal declaration.
	 * 
	 * @param internalDeclaration
	 *            The declaration.
	 */
	public ASVariableDeclarationStatement(AST ast,
			ASVariableDeclaration internalDeclaration) {
		this(ast);
		setDeclaration(internalDeclaration);
	}

	/**
	 * Returns the statement's declaration.
	 * 
	 * @return The declaration
	 */
	public ASVariableDeclaration getDeclaration() {
		return declaration;
	}

	/**
	 * Sets the statement's declaration.
	 * 
	 * @param declr
	 *            The declaration
	 */
	public void setDeclaration(ASVariableDeclaration declaration) {
		if (declaration == null) {
			throw new IllegalArgumentException();
		}
		ASTNode oldChild = this.declaration;
		preReplaceChild(oldChild, declaration, DECLARATION_PROPERTY);
		this.declaration = declaration;
		postReplaceChild(oldChild, declaration, DECLARATION_PROPERTY);

		this.setFullRegion((ASRegion) declaration.getFullRegion().clone());
	}

	//
	// ======== INTERNAL GETTER / SETTER
	//

	/*
	 * (omit javadoc for this method) Method declared on ASTNode.
	 */
	final ASTNode internalGetSetChildProperty(
			ASChildPropertyDescriptor property, boolean get, ASTNode child) {
		if (property == DECLARATION_PROPERTY) {
			if (get) {
				return getDeclaration();
			} else {
				setDeclaration((ASVariableDeclaration) child);
				return null;
			}
		}

		// allow default implementation to flag the error
		return super.internalGetSetChildProperty(property, get, child);
	}

	// ====== PARENT SETTING

	@Override
	public void setParent(ASTNode parent, ASPropertyDescriptor location) {
		super.setParent(parent, location);

		IScopeElement scope = getNearestScope();
		if (scope == null) {
			return;
		}

		scope.addToScope(getDeclaration());
	}

	/**
	 * Visitor implementation.
	 */
	@Override
	public void accept(IVisitor as2Visitor, boolean visitChilds) {
		visitChilds = as2Visitor.visit(this);

		if (!visitChilds) {
			return;
		}

		getDeclaration().accept(as2Visitor, visitChilds);
	}

	@Override
	public String toString() {
		return "s:" + getDeclaration().toString();
	}
}
